﻿using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using QuickGet.Core;
using QuickGet.Core.Models;
using QuickGet.Core.Stores;
using QuickGet.EntityFrameworkCore.Models;

namespace QuickGet.EntityFrameworkCore.Stores
{
    public class PackageStore : PackageStoreBase
    {
        public PackageStore(
            ILogger<PackageStore> logger, 
            IOptions<QuickGetOptions> options, 
            AppDbContext appDbContext) : base(logger, options)
        {
            AppDb = appDbContext;
        }

        protected virtual AppDbContext AppDb { get; set; }

        public override async Task<List<PackageVersionInfo>> GetDownloadedVersionsAsync(string packageId, CancellationToken cancellationToken)
        {
            var normalizedPackageId = NormalizePackageId(packageId);

            var query = AppDb.PackageVersions.AsNoTracking()
                .Where(x => x.PackageId == normalizedPackageId)
                .Select(x => new PackageVersionInfo(x.PackageId, x.PackageVersion, x.SavePath));

            return await query.ToListAsync(cancellationToken);
        }

        public override async Task<List<PackageInfo>> GetListAsync(CancellationToken cancellationToken)
        {
            var query = AppDb.Packages.AsNoTracking()
                .Select(row => new PackageInfo(row.PackageId, row.NormalizedPackageId));

            return await query.ToListAsync(cancellationToken);
        }

        public override async Task<string?> GetPackageDownloadPathAsync(string packageId, string version, CancellationToken cancellationToken)
        {
            var normalizedPackageId = NormalizePackageId(packageId);

            var query = AppDb.PackageVersions.AsNoTracking()
                .Where(x => x.PackageId == normalizedPackageId)
                .Select(x => x.SavePath);

            return await query.FirstOrDefaultAsync(cancellationToken);
        }

        public override async Task SaveAsync(string packageId, CancellationToken cancellationToken)
        {
            var entity = await AppDb.Packages
                .Where(x => x.PackageId == packageId)
                .FirstOrDefaultAsync(cancellationToken);

            if (entity is null)
            {
                var normalizedPackageId = NormalizePackageId(packageId);
                entity = new PackageEntity(packageId, normalizedPackageId);
                AppDb.Add(entity);
            }
            else
            {
                entity.LastModified = DateTimeOffset.UtcNow;
            }

            await AppDb.SaveChangesAsync(cancellationToken);
        }

        public override async Task SaveDownloadAsync(string packageId, string version, string path, CancellationToken cancellationToken)
        {
            var normalizedPackageId = NormalizePackageId(packageId);
            var normalizedPackageVersion = NormalizePackageVersion(version);

            var entity = await AppDb.PackageVersions.Where(x
                => x.PackageId == normalizedPackageId)
                .FirstOrDefaultAsync(cancellationToken);

            if (entity is null)
            {
                entity = new Models.PackageVersionEntity(normalizedPackageId, normalizedPackageVersion);
                entity.SavePath = path;

                AppDb.Add(entity);
            }
            else
            {
                entity.PackageVersion = normalizedPackageVersion;
                entity.SavePath = path;
                entity.LastModified = DateTimeOffset.UtcNow;
            }

            await AppDb.SaveChangesAsync(cancellationToken);
        }
    }
}
